
#include <iostream>
#include "File.h"
#include "Predicate.h"
#include "Record.h"
#include "Schema.h"
#include "BPlusTree.h"
#include "IndexRecord.h"
#include "TwoWayList.h"
#include "Attribute.h"


int main () {

	std::cout << "What do you want to do?\n";
	std::cout << "1. Load a text file into a binary database file.\n";
	std::cout << "2. Apply a selection predicate to a binary database file.\n";
	std::cout << "3. Find all records falling in a range using a B+-Tree.\n>";

	int choice;
	std::cin >> choice;
	
	if (choice == 1)
	{
		
		//case 1:
			std::cout << "What do you want to do?\n";
			std::cout << "1. Create a binary file without an index.\n";
			std::cout << "2. Create a binary file with a B+-Tree index.\n>";
			
			int choice2;
			std::cin >> choice2;
			
			if (choice2 == 1) {
				std::cout << "What is the name of the text file to load?\n>";
				char ans1[100];
				std::cin >> ans1;

				std::cout << "What is the name of the file where the schema is located?\n>";
				char ans2[100];
				std::cin >> ans2;

				std::cout << "What is the name of the relation schema?\n>";
				char ans3[100];
				std::cin >> ans3;

				std::cout << "Where should the binary file be stored?\n>";
				char ans4[100];
				std::cin >> ans4;

				// load in the relation's schema
				Schema mySchema (ans2, ans3);

				// open up the file
				File dbFile;
				dbFile.Open (0, ans4);

				// this will store the data
				Record temp;

				// this is the text file to process
				FILE *inFile = fopen (ans1, "r");

				// load it up
				int i;
				while (temp.SuckNextRecord (mySchema, inFile)) {
					if (i % 1000 == 0)
						std::cerr << ".";
					dbFile.Append (temp);
					++i;
				}
				std::cerr << "Done!\n";

				// and close it
				dbFile.Close ();
				
			}
			
			else if (choice2 == 2) {
			
				std::cout << "What is the name of the text file to load?\n>";
				char ans5[100];
				std::cin >> ans5;

				std::cout << "What is the name of the file where the schema is located?\n>";
				char ans6[100];
				std::cin >> ans6;

				std::cout << "What is the name of the relation schema?\n>";
				char ans7[100];
				std::cin >> ans7;

				std::cout << "Where should the binary file be stored?\n>";
				char ans8[100];
				std::cin >> ans8;
				
				std::cout << "What attribute would you like to index?\n>";
				char ans9[100];
				std::cin >> ans9;
				
				std::cout << "Where should the B+-Tree index file be stored?\n>";
				char ans10[100];
				std::cin >> ans10;
			
				// load in the relation's schema
				Schema mySchema (ans6, ans7);

				// open up the dbfile
				File dbFile;
				dbFile.Open (0, ans8);
				
				//open up the index file
				//File bptFile;
				//bptFile.Open(0, ans10);
				
			
				// this will store the data
				Record temp;
				
				//this will store the index
				
				int length = strlen(ans9);
				//ir_key.Load(ans5, length, 1);

				// this is the text file to process
				FILE *inFile = fopen (ans5, "r");
				
				
				Type type = mySchema.FindType ( mySchema.Find (ans9) );
				BPlusTree bpt;
				bpt.Create(ans10,type);
						 		
				// load it up
				int i;
				while (temp.SuckNextRecord (mySchema, inFile)) {
					
					if (i % 1000 == 0)
					{
						std::cerr << ".";
					}
					//	temp.Print (mySchema);
					
					
					
					IndexRecord ir_key;
					ir_key.ConsumeToIndexRecord( temp,mySchema,ans9/*,pgNum*/ );
					int pgNum;
					pgNum = dbFile.Append (temp);
					
					
					
					Attribute at = Attribute();
					ir_key.GetKey(at,type);//setting the key attribute equal to at
					
					char* theKey = at.GetString();
					bpt.Insert(theKey,pgNum);
					delete theKey;
					
					++i;
				}
				std::cerr << "Done!\n";

				// and close it
				dbFile.Close ();
				
			}
			
	}		//break;
			
	else if (choice == 2){
	 		std::cout << "What is the name of the file where the schema is located?\n>";
			char ans11[100];
			std::cin >> ans11;

			std::cout << "What is the name of the relation schema?\n>";
			char ans12[100];
			std::cin >> ans12;

			std::cout << "What is the name of the file where the selection predicate is stored?\n>";
			char ans13[100];
			std::cin >> ans13;

			std::cout << "What is the name of the binary data file?\n>";
			char ans14[100];
			std::cin >> ans14;

			// load in the relation's schema
			Schema mySchema (ans11, ans12);

			// load in the predicate
			Predicate myPred (mySchema, ans13);

			// open up the file
			File dbFile;
			dbFile.Open (1, ans14);

			// and scan the file
			Record temp;
			int i = 0;
			while (dbFile.NextRec (temp)) {
				++i;
				if (myPred.Apply (temp)) {
					temp.Print (mySchema);
				}
			}
		
			std::cerr << "\nDone!\n";
			dbFile.Close ();
		
	}		//break;
		
	else if (choice == 3){
			std::cout << "What is the name of the file where the schema is located?\n>";
			char ans15[100];
			std::cin >> ans15;

			std::cout << "What is the name of the relation schema?\n>";
			char ans16[100];
			std::cin >> ans16;

			std::cout << "What is the name of the binary data file?\n>";
			char ans17[100];
			std::cin >> ans17;
			
			std::cout << "What is the name of the attribute to be queried over?\n>";
			char ans18[100];
			std::cin >> ans18;

			std::cout << "What is the lower bound of the query range?\n>";
			char ans19[100];
			std::cin >> ans19;

			std::cout << "What is the upper bound of the query range?\n>";
			char ans20[100];
			std::cin >> ans20;

			std::cout << "What is the name of the B+-Tree file that will be used to answer the query?\n>";
			char ans21[100];
			std::cin >> ans21;
			
			Schema mySchema (ans15, ans16);
			
			
			File dbFile;
			dbFile.Open (1, ans17);
			
			//get type of key and set it equal to the argumemnt in the constructor
			Type type = mySchema.FindType ( mySchema.Find (ans18) );
			
			BPlusTree bpt;//( type );
			
			bpt.Open(ans21);
			
			
			Attribute at_low;
			Attribute at_high;
			switch( type )
			{
				case Int:
					at_low.LoadInt(*((int *) ans19));
					at_high.LoadInt(*((int *) ans20));
					break;
				case Double:
					at_low.LoadDouble(*((double *) ans19));
					at_high.LoadDouble(*((double *) ans20));
					break;
				case String:
					at_low.LoadString(ans19);
					at_high.LoadString(ans20);
					break;
				default:
					std::cout<<"default:"<<__LINE__<<std::endl;
					break;
			}
			
			
			int *result_list = NULL;
			int num_pages = 100;
			
			result_list == bpt.SearchKeyRange(num_pages, at_low, at_high);
			
			for(int i=0; i<num_pages; ++i)
			{
				Page p;
				IndexRecord r;
				dbFile.GetPage (p, result_list[i]);
				while(p.GetFirst(r))
				{
					//if (myPred.Apply (r)) {
					//	r.Print (mySchema);
					//}
				}
				
				
			}
			
			delete [] result_list;
			
			dbFile.Close();
			
	}		//break;
		
	else{	
			std::cout << "\nGood Bye!\n";

	}
}
